package com.ys.service.wallet.btc;

import cn.hutool.core.util.NumberUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSONObject;
import com.ys.entity.WalletAddress;
import com.ys.entity.WalletWithdraw;
import com.ys.entity.block.Transaction;
import com.ys.entity.block.btc.BtcAccountTransatcion;
import com.ys.entity.block.btc.BtcBlockEntity;
import com.ys.entity.block.btc.ValidateAddressInfo;
import com.ys.enu.CurrencyEnum;
import com.ys.enu.ResultCodeEnum;
import com.ys.service.wallet.base.AbstractWalletService;
import com.ys.web.base.ResultBody;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;

/**
 * 比特币 service
 */
@Service
@Data
@NoArgsConstructor
@AllArgsConstructor
@Slf4j
@ConfigurationProperties(prefix="wallet.btc")
public class BtcWalletService extends AbstractWalletService {

    private String username;
    private String password;
    private Integer currency;
    private CurrencyEnum currencyEnum;
    private String server;
    private String withDrawAddressPwd;
    private String withDrawAddress;
    private String depositAddress;
    private String pub;
    private String pri;

    private static Boolean FALSE=false;

    public ResultBody createAddress() {
        try {
            Object param = new Object[] {depositAddress};
            String  address=createRPCClient().invoke(createAddressMethod(), param, String.class);

            WalletAddress walletAddress=new WalletAddress();
            walletAddress.setAdress(address);
            walletAddress.setCurrency(getCurrency());
            walletAddress.setCurrencyChainType(currencyEnum().getCurrencyChainType());
            walletAddress.setAccount(depositAddress);//建立address 和account的绑定关系
            getWalletAddressServiceImap().insert(walletAddress);
            return  new ResultBody(ResultCodeEnum.success,address);
        } catch ( Throwable e) {
            log.error(currencyEnum.cName+"创建地址失败",e);
        }
        return new ResultBody(ResultCodeEnum.fail,"创建钱包失败");
    }

    public String createAddressMethod(){
        return "getnewaddress";
    }

    /**
     * 验证address 如果验证成功返回包含pubkey等属性的json
     * @param address 验证信息
     * @return
     */
    public ValidateAddressInfo validAddress(String address){

        Object param = new Object[] {address};
        try {
            ValidateAddressInfo  validateAddressInfo=createRPCClient().invoke("validateaddress", param, ValidateAddressInfo.class);
            return validateAddressInfo;
        } catch (Throwable throwable) {
            throwable.printStackTrace();
            log.error(currencyEnum.cName+"验证地址失败：",throwable);
            return null;
        }
    }

    /**
     * 根据地址查询 地址的私钥
     * TODO 是否加密存储
     * @param address
     * @return
     */
    public String queryPrikeyByAddress(String address){
        Object param = new Object[] {address};
        try {
            String  prikey=createRPCClient().invoke("dumpprivkey", param, String.class);
            return prikey;
        } catch (Throwable throwable) {
            throwable.printStackTrace();
            log.error(currencyEnum.cName+"查询地址私钥失败：",throwable);
            return null;
        }


    }

    /**
     * 比特币 考虑效率 应该用sendmany接口
     * @param walletWithdraw
     * @return
     */
    @Override
    public String sendWithDraw(WalletWithdraw walletWithdraw) {
        String amount=NumberUtil.decimalFormat("0.00000000",walletWithdraw.getWithdrawAmount().doubleValue());
        Object param = new Object[] {this.withDrawAddress,walletWithdraw.getToAddress(),amount};
        try {
            String  txId=createRPCClient().invoke("sendfrom", param, String.class);
            return txId;
        } catch (Throwable throwable) {
            throwable.printStackTrace();
            log.error(currencyEnum.cName+",提币失败：",throwable);
            log.error(currencyEnum.cName+"提币失败：", JSONUtil.toJsonStr(walletWithdraw));
            return null;
        }
    }

    @Override
    public String queryTransactionByHashMethod() {
        return "gettransaction";
    }

    @Override
    public String queryBlockByHash(String hash) {
        Object param = new Object[] {hash};
        try {
            BtcBlockEntity  btcBlockEntity=createRPCClient().invoke("getblock", param, BtcBlockEntity.class);
            if(btcBlockEntity!=null)
            return btcBlockEntity.getHeight()+"";
        } catch (Throwable throwable) {
            throwable.printStackTrace();
            log.error(currencyEnum.cName+"根据块hash查询块号失败：",throwable);
            return null;
        }
        return  null;
    }


    public List<BtcAccountTransatcion> listtransactions(String account,int offset){
        Object param = new Object[] {account,10,offset};
        try {
            List<BtcAccountTransatcion>  list=createRPCClient().invoke("listtransactions",
                    param, (new ArrayList<BtcAccountTransatcion>()).getClass());
            List<BtcAccountTransatcion> result=new ArrayList<>();
            for(Object obj:list){
                result.add(JSONObject.parseObject(JSONUtil.toJsonStr(obj),BtcAccountTransatcion.class));
            }
            return result;
        } catch (Throwable throwable) {
            throwable.printStackTrace();
            log.error(currencyEnum.cName+"根据块hash查询块号失败：",throwable);
            return null;
        }


    }

    @Override
    public String mostRecentBlockNumberMethod() {
        return "getblockcount";
    }

    /**
     * 比特币手续费 应该定时从数据库或redis中获取
     * @return
     */
    @Override
    public String gasPrice() {
        return "0.00000226";
    }

    @Override
    public String auth() {
        return this.username+":"+this.password;
    }

    @Override
    public String server() {
        return this.server;
    }

    @Override
    public CurrencyEnum currencyEnum() {
        return this.currencyEnum;
    }

   public void setCurrency(Integer currency) {
        this.currency = currency;
        this.currencyEnum=CurrencyEnum.parseCurrency(currency);
    }

    public static void main(String[] args) {
        System.out.printf(NumberUtil.decimalFormat("0.00000000",1111111.01d));
    }



}
